﻿using System;
using System.Collections.Generic;

namespace DotNet.Common.Utilities.Comparer
{
    /// <summary>
    /// IComparer辅助类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <example>
    ///     <code>
    ///         var comparer1 = Comparison<Person>.Create(p => p.ID);
    ///         var comparer2 = Comparison<Person>.Create(p => p.Name);
    ///         var comparer3 = Comparison<Person>.Create(p => p.Birthday.Year);
    ///         var comparer4 = Comparison<Person>.Create(p => p.Name, StringComparer.CurrentCultureIgnoreCase);
    ///     </code>
    /// </example>
    public static class Comparison<T>
    {
        public static IComparer<T> Create<V>(Func<T, V> keySelector)
        {
            return new CommonComparer<V>(keySelector);
        }
        public static IComparer<T> Create<V>(Func<T, V> keySelector, IComparer<V> comparer)
        {
            return new CommonComparer<V>(keySelector, comparer);
        }

        class CommonComparer<V> : IComparer<T>
        {
            private Func<T, V> keySelector;
            private IComparer<V> comparer;

            public CommonComparer(Func<T, V> keySelector, IComparer<V> comparer)
            {
                this.keySelector = keySelector;
                this.comparer = comparer;
            }
            public CommonComparer(Func<T, V> keySelector)
                : this(keySelector, Comparer<V>.Default)
            { }

            public int Compare(T x, T y)
            {
                return comparer.Compare(keySelector(x), keySelector(y));
            }
        }
    }

    /// <summary>
    /// IEqualityComparer辅助类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <example>
    ///     <code>
    ///         var equalityComparer1 = Equality<Person>.Create(p => p.ID);
    ///         var equalityComparer2 = Equality<Person>.Create(p => p.Name);
    ///         var equalityComparer3 = Equality<Person>.Create(p => p.Birthday.Year);
    ///         var equalityComparer4 = Equality<Person>.Create(p => p.Name, StringComparer.CurrentCultureIgnoreCase);
    ///     </code>
    /// </example>
    public static class Equality<T>
    {
        /// <summary>
        /// 生成一个通用比较类
        /// </summary>
        /// <typeparam name="V"></typeparam>
        /// <param name="keySelector"></param>
        /// <returns></returns>
        public static IEqualityComparer<T> Create<V>(Func<T, V> keySelector)
        {
            return new CommonEqualityComparer<V>(keySelector);
        }
        /// <summary>
        /// 生成一个通用比较类2
        /// </summary>
        /// <typeparam name="V"></typeparam>
        /// <param name="keySelector"></param>
        /// <param name="comparer"></param>
        /// <returns></returns>
        public static IEqualityComparer<T> Create<V>(Func<T, V> keySelector, IEqualityComparer<V> comparer)
        {
            return new CommonEqualityComparer<V>(keySelector, comparer);
        }

        /// <summary>
        /// 嵌套的通用比较类
        /// </summary>
        /// <typeparam name="V"></typeparam>
        class CommonEqualityComparer<V> : IEqualityComparer<T>
        {
            private Func<T, V> keySelector;
            private IEqualityComparer<V> comparer;

            public CommonEqualityComparer(Func<T, V> keySelector, IEqualityComparer<V> comparer)
            {
                this.keySelector = keySelector;
                this.comparer = comparer;
            }
            public CommonEqualityComparer(Func<T, V> keySelector)
                : this(keySelector, EqualityComparer<V>.Default)
            { }

            public bool Equals(T x, T y)
            {
                return comparer.Equals(keySelector(x), keySelector(y));
            }
            public int GetHashCode(T obj)
            {
                return comparer.GetHashCode(keySelector(obj));
            }
        }
    }

    /// <summary>
    /// 通用比较类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="V"></typeparam>
    public class CommonEqualityComparer<T, V> : IEqualityComparer<T>
    {
        private Func<T, V> keySelector;
        private IEqualityComparer<V> comparer;

        public CommonEqualityComparer(Func<T, V> keySelector, IEqualityComparer<V> comparer)
        {
            this.keySelector = keySelector;
            this.comparer = comparer ?? EqualityComparer<V>.Default;

        }

        public bool Equals(T x, T y)
        {
            return comparer.Equals(keySelector(x), keySelector(y));

        }

        public int GetHashCode(T obj)
        {
            return comparer.GetHashCode(keySelector(obj));

        }
    }
}
